package com.vietnam.power.dao.impl;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.vietnam.power.constant.ProductConstant;
import com.vietnam.power.dao.ProductDao;
import com.vietnam.power.domain.ProductSearchDTO;
import com.vietnam.power.persistence.Category;
import com.vietnam.power.persistence.Product;

@Repository
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public class ProductDaoImpl extends GenericDaoImpl implements ProductDao {

	@SuppressWarnings("unchecked")
	public List<Product> getProductByCriteria(ProductSearchDTO searchDTO) {
		Criteria criteria = getActiveSession().createCriteria(Product.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		// keyword: ilike product name or description
		if (searchDTO.getKeyword() != null) {
			criteria.add(Restrictions.or(Restrictions.ilike("productName", searchDTO.getKeyword(), MatchMode.ANYWHERE),
					Restrictions.ilike("description", searchDTO.getKeyword(), MatchMode.ANYWHERE)));
		}
		// max price
		if (searchDTO.getMaxPrice() != null) {
			criteria.add(Restrictions.le("unitPrice", searchDTO.getMaxPrice()));
		}
		// min price
		if (searchDTO.getMinPrice() != null) {
			criteria.add(Restrictions.ge("unitPrice", searchDTO.getMinPrice()));
		}
		// category
		if (searchDTO.getProductCatId() != null) {
			criteria.createAlias("category", "category");
			criteria.add(Restrictions.eq("category.categoryId", searchDTO.getProductCatId()));
		}

		if (searchDTO.getSortBy() != null) {
			if (searchDTO.getSortBy().equals(ProductConstant.SortBy.RECENT.getSortId())) {
				criteria.addOrder(Order.desc("updatedDate"));
			} else if (searchDTO.getSortBy().equals(ProductConstant.SortBy.HIGHEST_PRICE.getSortId())) {
				criteria.addOrder(Order.desc("unitPrice"));
			} else if (searchDTO.getSortBy().equals(ProductConstant.SortBy.LOWEST_PRICE.getSortId())) {
				criteria.addOrder(Order.asc("unitPrice"));
			}
			if (searchDTO.getSortBy().equals(ProductConstant.SortBy.POPULAR.getSortId())) {
				criteria.addOrder(Order.asc("updatedDate"));
			}
		}

		if (searchDTO.getOwnerId() != null) {
			criteria.createAlias("createdBy", "createdBy");
			criteria.add(Restrictions.ge("createdBy.userInfoId", searchDTO.getMinPrice()));
		}

		criteria.setFirstResult(searchDTO.getPage());
		criteria.setMaxResults(searchDTO.getMaxResult());

		return criteria.list();
	}

	public Long countProductsByCriteria(ProductSearchDTO searchDTO) {
		Criteria criteria = getActiveSession().createCriteria(Product.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		// keyword: ilike product name or description
		if (searchDTO.getKeyword() != null) {
			criteria.add(Restrictions.or(Restrictions.ilike("productName", searchDTO.getKeyword(), MatchMode.ANYWHERE),
					Restrictions.ilike("description", searchDTO.getKeyword(), MatchMode.ANYWHERE)));
		}
		// max price
		if (searchDTO.getMaxPrice() != null) {
			criteria.add(Restrictions.le("unitPrice", searchDTO.getMaxPrice()));
		}
		// min price
		if (searchDTO.getMinPrice() != null) {
			criteria.add(Restrictions.ge("unitPrice", searchDTO.getMinPrice()));
		}
		// category
		if (searchDTO.getProductCatId() != null) {
			criteria.createAlias("category", "category");
			criteria.add(Restrictions.eq("category.categoryId", searchDTO.getProductCatId()));
		}

		if (searchDTO.getSortBy() != null) {
			if (searchDTO.getSortBy().equals(ProductConstant.SortBy.RECENT.getSortId())) {
				criteria.addOrder(Order.desc("updatedDate"));
			} else if (searchDTO.getSortBy().equals(ProductConstant.SortBy.HIGHEST_PRICE.getSortId())) {
				criteria.addOrder(Order.desc("unitPrice"));
			} else if (searchDTO.getSortBy().equals(ProductConstant.SortBy.LOWEST_PRICE.getSortId())) {
				criteria.addOrder(Order.asc("unitPrice"));
			}
			if (searchDTO.getSortBy().equals(ProductConstant.SortBy.POPULAR.getSortId())) {
				criteria.addOrder(Order.asc("updatedDate"));
			}
		}

		if (searchDTO.getOwnerId() != null) {
			criteria.createAlias("createdBy", "createdBy");
			criteria.add(Restrictions.ge("createdBy.userInfoId", searchDTO.getOwnerId()));
		}

		criteria.setProjection(Projections.rowCount());

		return (Long) criteria.uniqueResult();
	}

	public Product getProductById(Long id) {
		return findById(Product.class, id);
	}

	@SuppressWarnings("unchecked")
	public List<Category> getAllParentCategories() {
		Criteria criteria = getActiveSession().createCriteria(Category.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		criteria.add(Restrictions.isNull("category"));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	public List<Category> getAllChildrenCategories(Long parentId) {
		Criteria criteria = getActiveSession().createCriteria(Category.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		criteria.createAlias("categoryId", "parentCate");
		criteria.add(Restrictions.eq("parentCate.categoryId", parentId));
		return criteria.list();
	}
}
